#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <qmessagebox.h>
#include <qfiledialog.h>
#include <qdebug.h>
#include <QTime>
#include <QTextCodec>
#include <qprocess.h>
#include <QCryptographicHash>
#include "qaesencryption.h"
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    this->setWindowTitle("TC - Decrypter  By:奇怪的码农");
    this->setWindowIcon(QIcon("bird.ico"));
    InitStyle();
    LogStr("选择一个TC编译的exe程序 尝试提取、反编译");
    zip7Init();
    //    QString str = "123456正";
    //    QByteArray qbyte = str.toLocal8Bit();
    //    QByteArray la = str.toLatin1();
    //    qDebug()<<QCryptographicHash::hash(qbyte,QCryptographicHash::Md5).toHex();
    //    存在中文时 转为QbyteArray  toLatin1 一般为ASCll 当出现汉字时 只读一个字节 导致结果出错
    //    ui->progressBar->setValue(0);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::InitStyle()
{
    //加载样式表
    QFile file(":/qss/psblack.css");
    if (file.open(QFile::ReadOnly)) {
        QString qss = QLatin1String(file.readAll());
        QString paletteColor = qss.mid(20, 7);
        qApp->setPalette(QPalette(QColor(paletteColor)));
        qApp->setStyleSheet(qss);
        file.close();
    }
}


void MainWindow::on_pushButton_clicked()
{
    //    浏览文件

    QFileDialog* qfd = new QFileDialog(this);
    qfd->setWindowTitle("选择TC EXE程序");
    qfd->setFileMode(QFileDialog::ExistingFiles); //只选择一个文件
    QStringList fileNames;
    if (qfd->exec())
    {
        fileNames = qfd->selectedFiles();
    }
    if(fileNames.isEmpty())
    {
        QMessageBox::information(this,"错误","请选择一个EXE文件");
        return;
    }

    ui->lineEdit->setText(fileNames.at(0));
    LogStr("选择完毕 路径:"+fileNames.at(0));

}
void MainWindow::LogStr(QString str)
{
    ui->plainTextEdit->appendPlainText(str);
}

bool MainWindow::zip7Init()
{
    QStringList strlist =  QStringList();
    strlist.append("7z.exe");
    strlist.append("7z.dll");
    for (QString fileName:strlist) {
        QString LocalFile = QApplication::applicationDirPath()+"/"+fileName;
        //        拷贝资源文件到本地
        qDebug()<<LocalFile;
        if(!QDir().exists(LocalFile)){
            return  QFile::copy(":/other/res/"+fileName,LocalFile);
        }
    }
    return true;
}
bool MainWindow::Zip(QString dest,QString src_partten,QString &out){
    QString filestate = "";
    out = "";
    if(zip7Init()==false){
        LogStr("不能执行压缩");
        return false;
    }
    else{
        QProcess p(0);
        QStringList args = QStringList();
        args.append("a");
        args.append(dest);
        args.append(src_partten);
        p.start(QApplication::applicationDirPath() + "/7z.exe",args);
        p.waitForStarted();
        p.waitForFinished();
        out = QString::fromLocal8Bit(p.readAllStandardOutput());
        return true;
    }
}
bool MainWindow::UnZip(QString src,QString dest,QString &out){
    QString filestate = "";
    out = "";
    if(zip7Init()==false){
        LogStr("不能执行解压缩");
        return false;
    }
    else{
        QProcess p(0);
        QStringList args = QStringList();
        args.append("x");
        args.append(src);
        args.append("-o" + dest);//-o和目标目录必须连在一起
        args.append("-aoa");//不提示,直接覆盖同名文件
        p.start(QApplication::applicationDirPath() + "/7z.exe",args);
        p.waitForStarted();
        p.waitForFinished();
        out = QString::fromLocal8Bit(p.readAllStandardOutput());

        return true;
    }
}

QByteArray MainWindow::instruct_parse(QByteArray bytes,bool isDec=false)
{
//    指令解析
    QByteArray newArr;
    newArr = bytes;

    if(newArr.length() == 4 && !isDec)
    {
//        161-175
        for (int j=0;j<4;j++) {
            unsigned char ch = newArr.at(j);
            if(ch<161 | ch>175)
            {
                newArr[j] = newArr.at(j)^MainWindow::seed;
            }
        }
       QString binStr =QString(newArr.toHex().toUpper());
//        SaveString.append(binStr);
         return newArr;
       if(binStr == "A7A6A5A4")
           SaveString.append("变量");
        return newArr;
//       if(binStr == "A8A6A9AC")
//           SaveString.append("功能");
//       if(binStr == "A3A8A8A8")
//           SaveString.append("结束");
//       if(binStr == "A8A7A6A5")
//           SaveString.append("赋值");
//       表示下面是系统命令
//       if(binStr == "AAA9A8A7")
//           SaveString.append("如果");
        return newArr;
    }
    for (int i=0;i<bytes.length();i++) {
        unsigned char ch = bytes.at(i);
        switch (ch) {
        case 18:
            newArr[i] = 61;
            break;
        case 25:
            newArr[i] = 34;
            break;
        case 20:
            newArr[i] = 44;
            break;
        case 11:
            newArr[i] = 40;
            break;
        case 19:
            newArr[i] = 41;
            break;
        case 24:
            newArr[i] = '&';
            break;
        case 0xf:
            newArr[i] = '>';
            break;
        case 0x10:
            newArr[i] = '<';
            break;
        }

    }
    return newArr;
}



void MainWindow::on_pushButton_2_clicked()
{
    //    zip提取

    // 获取指定模块里的指定资源
    QString pathStr = ui->lineEdit->text();
    //    QTextCodec* code = QTextCodec::codecForName("gb18030");
    //    pathStr = code->fromUnicode(pathStr);
    if(pathStr.isEmpty())
    {
        LogStr("错误....     请先选择文件！");
        return;
    }

    QFile fs(pathStr);
    QString FileName = fs.fileName();
    LogStr("文件名：" + FileName);

    if(!(fs.open(QIODevice::ReadOnly))){
        LogStr("错误.... 文件被占用！");
        return;
    }

    QByteArray byteArr = fs.readAll();
    qDebug()<<"读取的字节大小："+QString::number(byteArr.length());
    QByteArray hashArr = QCryptographicHash::hash(byteArr,QCryptographicHash::Md5);
    LogStr("EXE-Hash:"+hashArr.toHex());
    fs.close();


    QByteArray loadArg = pathStr.toLocal8Bit();
    //QString::fromLocal8Bit(str.data());
    //    QString 与 char* 相互转换 解决中文乱码
    HMODULE hmod = LoadLibraryA(loadArg.data());
    if(!hmod){
        LogStr("错误.... 载入模块失败！");
        return;
    }
    HRSRC hFind = FindResourceA(hmod,(LPCSTR)0x8B,"LC");
    if(!hFind){
        LogStr("错误.... 寻找资源失败");
        return;
    }
    HGLOBAL hLoad = LoadResource(hmod,hFind);
    if(!hLoad){
        LogStr("错误.... 载入资源失败");
        return;
    }
    LockResource(hLoad);
    SIZE_T resoureSize = SizeofResource(hmod,hFind);
    LogStr("资源大小："+QString::number(resoureSize));
    unsigned char* readbuff = (unsigned char*)malloc(resoureSize);
    ReadProcessMemory((HANDLE)-1,hLoad,readbuff,resoureSize,&resoureSize);
    LogStr("解析资源");
    *readbuff = 55;
    *(readbuff+2) = 0xBC;
    *(readbuff+3) = 0xAF;
    //    修改文件标志位
    //    此处为7z文件头部,改动大概1-3字节，要改回原始头，否则7z无法识别


    QString nFileName = QString(hashArr.toHex());
    QString savepathName= "src/"+nFileName+".zip";
    QFile file(savepathName);
    qDebug()<<QDir::currentPath();
    QDir dir(QDir::currentPath()+"/src");
    dir.mkdir(QDir::currentPath()+"/src/"+nFileName);
    if(!dir.exists()) {
        LogStr("创建目录");
        dir.mkdir(QDir::currentPath()+"/src");
    }
    if(!file.open(QIODevice::WriteOnly))
    {
        LogStr("错误.... 打开文件失败!");
        free(readbuff);
        return;
    }

    if(! file.write((const char*)readbuff,resoureSize))
    {
        LogStr("错误.... 写入文件失败 2 !");
        free(readbuff);
        return;
    }
    file.close();
    LogStr("提取完毕! 文件："+savepathName);
    //    释放内存
    free(readbuff);
    QString out;
    UnZip(QDir::currentPath()+"/"+savepathName,QDir::currentPath()+"/src/"+nFileName,out);

    LogStr("解压完毕! 保存路径 现在可以尝试解密源码了哦！");
    workDir = QDir::currentPath()+"/src/"+nFileName;


}

void MainWindow::on_pushButton_3_clicked()
{
    //    开始解密源码
    //    处理tis文件
    // QMessageBox::information(this, "解密说明",  "由于时间和精力有限，大概只还原出他的基本语句，如TC系统功能语句，" \
    "文件中用 ___7b13(参数) 类似格式替代，流程控制语句也没发现，可能存于EXE资源中或链表(猜测),当然本人对于编译原理和解释器并无过多研究,"\
    "因此，本还原是尚需完善，要完美还原可能还需大量功能要做。"\
    "");

    QFile fs(workDir+"/intermediate.tis");
    if(!fs.open(QIODevice::ReadOnly))
    {
        LogStr(" 错误 文件打开失败！");
        return;
    }
    QByteArray byteArray = fs.readAll();
    QByteArray wfindArray;
    //    定义字节数组
    QString HexStr = "0D000A00FF00FF00";
    QByteArray wFind = HexStr.toLatin1();
    wfindArray =wfindArray.fromHex(wFind);

    QByteArrayList SaveArrayList;
    //    寻找字节数组
    int from_pos=0;
    while (true) {
        int find_pos = byteArray.indexOf(wfindArray,from_pos);
        if(find_pos <= 0)
        {
            break;
        }
        QByteArray temArray = byteArray.mid(from_pos,find_pos - from_pos);
        if(!temArray.isEmpty())
        {
                SaveArrayList.append(temArray);
        }

        from_pos = find_pos + 8;
    }
    LogStr("解析数据完毕 准备解密!");
    //    477A7A51313555380A48513537510E4C EFFB7A51313555384A4851353751D04C
//    setkey  计算出key值
//    计算seed值
QByteArray seedArr = SaveArrayList.at(0);
unsigned char tmpch;
unsigned char sedch = seedArr.at(0);
if(sedch == 0xA7)
{
    MainWindow::seed =seedArr.at(1)^0xA6;
}
else{
    MainWindow::seed =seedArr.at(3)^0xA7;
}

qDebug()<<seed;
QByteArray DecKey;
//    QByteArray DecKey = QByteArray::fromHex(QString("477A7A51313555380A48513537510E4C").toLatin1());
    DecKey.append(MainWindow::seed|0x47);
    DecKey.append((MainWindow::seed+1)|0x7A);
    DecKey.append(QByteArray::fromHex(QString("7A5131355538").toLatin1()));
    DecKey.append((MainWindow::seed+3)&0x4A);
    DecKey.append(QByteArray::fromHex(QString("4851353751").toLatin1()));
    DecKey.append(QByteArray::fromHex(QByteArray::number(MainWindow::seed*2,16)));
    DecKey.append(0x4C);

//     DecKey = QByteArray::fromHex(QString("477A7A51313555380A48513537510E4C").toLatin1());
    QByteArray NextDecKey;
    for (int i=0;i<SaveArrayList.length();i++) {

        if(NextDecKey.isEmpty())
        {
            NextDecKey = DecKey;
        }

        QByteArray tmpArr = SaveArrayList.at(i);

        if(tmpArr.length() == 4)
        {
            instruct_parse(tmpArr);
            continue;
        }

        unsigned char decLen = tmpArr[0];
        unsigned char encLen = tmpArr[4];
        QByteArray EncrypData = tmpArr.mid(8,encLen);
        QAESEncryption encryption(QAESEncryption::AES_128, QAESEncryption::ECB, QAESEncryption::ZERO);
        QByteArray DecyptData =  encryption.decode(EncrypData,NextDecKey);
        DecyptData = DecyptData.left(decLen);
        QString text = QString::fromWCharArray((wchar_t*)DecyptData.data(),decLen/2);

//        解密成功,开始指令集替换
        QByteArray codeR = text.toLocal8Bit();
        codeR = instruct_parse(codeR,true);
        text = QString::fromLocal8Bit(codeR);
        SaveString.append(text);
        LogStr(text);
        NextDecKey = tmpArr.left(16);


    }

}

void MainWindow::on_pushButton_5_clicked()
{
    //    解密tis文件

//    QMessageBox::question(this, "友情提示",  "本功能将单独解密tis文件，需要选择一个tis文件," \
//                                         "一般来说,处理不能提取的exe文件,例如官方自带验证和加壳的"\
//                                         "EXE,此时需要手动提取他释放的资源，其核心文件为*.tis,此为源码加密文件."\
//                                         "",QMessageBox::Yes | QMessageBox::No ,QMessageBox::NoButton);
    QMessageBox::information(this,"wait","等待添加");

}

void MainWindow::on_pushButton_6_clicked()
{
//    代码美化
    ui->plainTextEdit->setPlainText("");
    for (int i=0;i<SaveString.length();i++) {
   if( SaveString.at(i).indexOf(".t")>0 && SaveString.at(i).indexOf(":")>0)
   {
       continue;
   }

   QByteArray byteArr = SaveString.at(i).toLatin1();
   bool IsNumb = true;
   for (int j=0;j<byteArr.length();j++) {
       if(byteArr.at(j)>='0' && byteArr.at(j)<='9')
          {
           continue;
       }
      else{
       IsNumb = false;
       break;
       }

   }
   if(!IsNumb){
       if(SaveString.at(i) == "()"){
         ui->plainTextEdit->insertPlainText(SaveString.at(i));
       }
       else{
           LogStr(SaveString.at(i));
       }

   }


    }
}

void MainWindow::on_pushButton_4_clicked()
{
    QMessageBox::information(this,"wait","等待添加");
}
